#include "files.h"
#include "../std/systemcall.h"
#include "../std/errno.h"


/*Imprime el tipo y los permisos del archivo pasado como parametro*/
void printMode(File_info file){
	
	switch(file.type){
		case(0):printk("d");break;
		case(1):printk("-");break;
		case(2):printk("p");break;
		default:printk("-");break;	
	}
	
	unsigned int mode[3];
	int i;
	for(i=2; i>=0;i--){
		mode[i]=file.mode % 10;
		file.mode /= 10;
	}	
	for(i=0; i<3;i++){
		(mode[i] & 4)? printk("r"):printk("-");
		(mode[i] & 2)? printk("w"):printk("-");
		(mode[i] & 1)? printk("x"):printk("-");
	}
		printk("\t");
}

/*Lista los archivos del directorio requerido. Se pasa como argumento las opciones y el path en cualquier orde: las opciones disponibles son -a y -l*/
int ls_shell(int argc, char* argv[]){
	
	char* name=".";
	
	int alls=0;
	int full=0;
	int imp=0;
	
	int i, j;
	for(i=0;i<argc;i++){
		if(argv[i][0] == '-'){
			for(j=1;j<strlen(argv[i]);j++)			
				switch(argv[i][j]){
					case 'a': alls=1;break;
					case 'l': full=1;break;
					default: ;
				
				}
		}else
			name=argv[i];
	} 
	
	/*Si es link lo resuelvo*/
	getLinkPath(name);
	
	int fd=open(name,O_RD);
	
	if(fd==-1){
		printf("ls: error:%s\n",strerror(errno));
		return -1;
	}
	
	
	/*if(!hasPermission(dir, READ_PERMISSION)){
		printk("ls: Permission denied\n");
		return -1;
	}*/
	
	char sector[SECTOR_SIZE];
	
	while(__read(fd,sector,SECTOR_SIZE)){
	
		DirData* dirData=(DirData*)sector;
		
		for(i=0; i< dirData->eNodeCant; i++){
			if(alls || dirData->list[i].name[0]!='.'){
			
				if(full){ 
					File_info file;
					finfo(dirData->list[i].sector,&file);
					printMode(file); 
					printk("%s\t", file.owner); 
					printk("%s\t", file.group);
				}
				printk("%s\t", dirData->list[i].name);
				imp++;
				if(full) printk("\n");
			}
		}
	}
	
	if(imp && !full) printk("\n");

	return 0;	
}

/*Devuelve el sector del archivo "name", siendo este el hijo del derectorio abierto en el "fd"*/
int getSector(int fd,char* name){
	
	lseek(fd,0);
	
	char sector[SECTOR_SIZE];
	
	while(__read(fd,sector,SECTOR_SIZE)){
	
		DirData* dirData=(DirData*)sector;
		
		
		int i;
		for(i=0; i< dirData->eNodeCant; i++){
			if(strcmp(dirData->list[i].name,name)==0){
				return dirData->list[i].sector;
			}
		}
	}

	return -1;
}


int softLink(char * argv0, char * argv1){	
	
	char Oname[FILE_NAME], Dname[FILE_NAME];
	int origenDir, destinoDir;
	int origenSector, destinoSector;
	
	getParentPath(Oname, argv0);

	if(strlen(Oname)== 0){
		strcpy(Oname,".");
	}
	
	origenDir=open(Oname,0);
	
	if(origenDir==-1){
		printf("ln: error:%s\n",strerror(errno));
		return -1;
	}
	
	getParentPath(Dname, argv1);
	
	if(strlen(Dname)== 0){
		strcpy(Dname,".");
	}
	
	destinoDir=open(Dname,0);
	
	if(destinoDir==-1){
		printf("ln: error:%s\n",strerror(errno));
		return -1;
	}
	
	char fileOrigenName[FILE_NAME];
	char fileDestinoName[FILE_NAME];
	getLastNode(fileOrigenName, argv0);
	getLastNode(fileDestinoName, argv1);
  	
  	origenSector = getSector(origenDir,fileOrigenName);
  	
	/*Si no existe el archivo salgo*/
	if(origenSector == -1 ){	
		printf("ln: %s: File  doesn't exist\n", argv0);
		return -1;	
	}
	
	destinoSector = getSector(destinoDir,fileDestinoName);
	
	if(destinoSector != -1 ){	
		printf("%s: File  already  exist\n", argv1);
		return -1;	
	}
	
	int fd=open(argv1,O_CREATE | O_WR);
	
	if(fd==-1){
		printf("ln: could not create the file\n");
		return -1;
	}
	char path[MAX_PATH+3];
	strcpy(path, "\x1BL");
	getFilePath(path+2, argv0);
	__write(fd,path,strlen(path));
	
	close(fd);
	return 0;
	
}


int hardLink(char * argv0, char * argv1){	
	
	char Oname[FILE_NAME], Dname[FILE_NAME];
	int origenDir, destinoDir;
	int origenSector, destinoSector;
	
	getParentPath(Oname, argv0);

	if(strlen(Oname)== 0){
		strcpy(Oname,".");
	}
	
	origenDir=open(Oname,0);
	
	if(origenDir==-1){
		printf("ln: error:%s\n",strerror(errno));
		return -1;
	}
	
	getParentPath(Dname, argv1);
	
	if(strlen(Dname)== 0){
		strcpy(Dname,".");
	}
	
	destinoDir=open(Dname,0);
	
	

	if(destinoDir==-1){
		printf("ln: error:%s\n",strerror(errno));
		return -1;
	}
	
	char fileOrigenName[FILE_NAME];
	char fileDestinoName[FILE_NAME];
	getLastNode(fileOrigenName, argv0);
	getLastNode(fileDestinoName, argv1);
  	
  	origenSector = getSector(origenDir,fileOrigenName);
  	
	/*Si no existe el archivo salgo*/
	if(origenSector == -1 ){	
		printf("%s: File  doesn't exist\n", argv0);
		return -1;	
	}
	
	File_info origenInfo;
	finfo(origenSector,&origenInfo);
	if(origenInfo.type == DIRECTORY_TYPE){	
		printf("ln: Can not make directory hard links\n");
		return -1;		
	}
	
	destinoSector = getSector(destinoDir,fileDestinoName);
	
	if(destinoSector != -1 ){	
		printf("%s: File  already  exist\n", argv1);
		return -1;		
	}
	
	add_enode(destinoDir, fileDestinoName, origenSector);
	
	fcount(origenSector,1);
	
	return 0;	
	
}


/*Crea un link. El primer parametro es el archivo origen y el segundo es el archivo destino*/
int ln_shell(int argc, char* argv[]){
	
	if(argc<2){
		printf("usage: ln <pathname origin> <pathname destiny>\n");
		return -1;
	}
	if(argc==2)		
		return hardLink(argv[0], argv[1]);
	
	if(strcmp(argv[0], "-s")==0)
		return softLink(argv[1], argv[2]);
		
	return 0;
}


/*Mueve un archivo siendo el primer parametro el archivo origen y el segundo el destino*/
int mv_shell(int argc, char* argv[]){

	if(argc<2){
		printf("usage: mv <pathname origin> <pathname destiny>\n");
		return -1;
	}
	
	char Oname[FILE_NAME], Dname[FILE_NAME];
	int origenDir, destinoDir;
	int origenSector, destinoSector;
	
	getParentPath(Oname, argv[0]);

	if(strlen(Oname)== 0){
		strcpy(Oname,".");
	}
	
	origenDir=open(Oname,0);
	
	if(origenDir==-1){
		printf("mv: error:%s\n",strerror(errno));
		return -1;
	}
	
	getParentPath(Dname, argv[1]);
	
	if(strlen(Dname)== 0){
		strcpy(Dname,".");
	}
	
	destinoDir=open(Dname,0);
	
	
	
	if(destinoDir==-1){
		printf("mv: error:%s\n",strerror(errno));
		return -1;
	}
	
	char fileOrigenName[FILE_NAME];
	char fileDestinoName[FILE_NAME];
	getLastNode(fileOrigenName, argv[0]);
	getLastNode(fileDestinoName, argv[1]);
  	
  	origenSector = getSector(origenDir,fileOrigenName);
  	
	/*Si no existe el archivo salgo*/
	if(origenSector == -1 ){	
		printf("%s: File  doesn't exist\n", argv[0]);
		return -1;	
	}
	
	destinoSector = getSector(destinoDir,fileDestinoName);
	
	if(destinoSector != -1 ){	
		printf("%s: File  already  exist\n", argv[1]);
		return -1;		
	}
	
	rm_enode(origenDir, fileOrigenName);
	add_enode(destinoDir, fileDestinoName, origenSector);
	
	
	return 0;
	
}

	
	
int copyFileContent(char * source, char * destiny){	

	int fdSource=open(source,O_RD);	
	if(fdSource == -1){
		printf("cp: %s: could not open the file\n", source);
		return -1;
	}
	int fdDestino=open(destiny,O_CREATE | O_WR);	
	if(fdDestino == -1){
		printf("cp: %s: could not open the file\n", destiny);
		close(fdSource);
		return -1;
	}
	
	char buff[512];
	
	int num=1;	
	while(num!=0){
		if((num = __read(fdSource,buff,512))==-1){
			printf("cp: %s: could not read the file\n", source);
			close(fdSource);
			close(fdDestino);
			return 1;
		}
		__write(fdDestino,buff,num);
	}
	
	close(fdSource);
	close(fdDestino);
}	

int cp_shell(int argc, char* argv[]){
	
	if(argc<2){
		printf("usage: cp <pathname source> <pathname destiny>\n");
		return -1;
	}

	if(recursivePath(argv[0])){
		printf("cp: The path %s is not allowed\n", argv[0]);
		return -1;		
	}

	if(recursivePath(argv[1])){
		printf("cp: The path %s is not allowed\n", argv[1]);
		return -1;		
	}
	
	return 	_cp(argv[0], argv[1]);	
}	
	
int _cp(char * argv0, char * argv1){
	
	char Sname[FILE_NAME], Dname[FILE_NAME];
	int sourceDir, destinoDir;
	int sourceSector, destinoSector;
	
	getParentPath(Sname, argv0);
	if(strlen(Sname)== 0){
		strcpy(Sname,".");
	}
	
	getParentPath(Dname, argv1);
	if(strlen(Dname)== 0){
		strcpy(Dname,".");
	}
	
	sourceDir=open(Sname,0);
	
	if(sourceDir==-1){
		printf("cp: error:%s\n",strerror(errno));
		return -1;
	}
	
	destinoDir=open(Dname,0);
	
	if(destinoDir==-1){
		printf("mv: error:%s\n",strerror(errno));
		return -1;
	}
	
	char fileSourceName[FILE_NAME];
	char fileDestinoName[FILE_NAME];
	getLastNode(fileSourceName, argv0);
	getLastNode(fileDestinoName, argv1);
	
 	
  	sourceSector = getSector(sourceDir,fileSourceName);
  	
	/*Si no existe el archivo salgo*/
	if(sourceSector == -1 ){	
		printf("%s: File  doesn't exist\n", argv0);
		return -1;	
	}
	
	destinoSector = getSector(destinoDir,fileDestinoName);
	
	if(destinoSector != -1 ){	
		printf("%s: File  already  exist\n", argv1);
		return -1;		
	}
	
	
	File_info file;
	finfo(sourceSector,&file);

	if(file.type == DIRECTORY_TYPE){
		if(mknode(argv1,775,DIRECTORY_TYPE)==1){
			printf("cp: error:%s\n",strerror(errno));
			return -1;
		}
		
		int fdSource=open(argv0,O_RD);	
		if(fdSource == -1){
			printf("cp: %s: could not open the file\n", argv0);
			return -1;
		}
		
		char sector[SECTOR_SIZE];
		char newPath0[MAX_PATH];
		char newPath1[MAX_PATH];
		while(__read(fdSource,sector,SECTOR_SIZE)){
		
			DirData* dirData=(DirData*)sector;
			int i;
			for(i=0; i< dirData->eNodeCant; i++){
				if( strcmp(dirData->list[i].name,".") != 0 &&	
					strcmp(dirData->list[i].name,"..") != 0){
				
						strcpy(newPath0, argv0);
						strcpy(newPath0+strlen(argv0), "/");
						strcpy(newPath0+strlen(argv0)+1, dirData->list[i].name);
						strcpy(newPath0+strlen(argv0)+strlen(dirData->list[i].name)+1, "\0");
											
						strcpy(newPath1, argv1);
						strcpy(newPath1+strlen(argv1), "/");
						strcpy(newPath1+strlen(argv1)+1, dirData->list[i].name);
						strcpy(newPath1+strlen(argv1)+strlen(dirData->list[i].name)+1, "\0");
				
						_cp(newPath0, newPath1);
				}
			}
		}
		
		
	}else
		copyFileContent(argv0,argv1);

	return 0;
}

int _rm(char* path){
	if(recursivePath(path)){
		return -2;		
	}
	
	char name[FILE_NAME];
	int file_sector;
	
	getParentPath(name, path);

	if(strlen(name)== 0){
		strcpy(name,".");
	}
	
	int dir=open(name,0);
	
	if(dir==-1){
		return -1;
	}
	
	char fileToRemove[FILE_NAME];
	getLastNode(fileToRemove, path);
	
	file_sector = getSector(dir,fileToRemove);
  	
  	if(file_sector == -1){
 		return -1;
 	}
  	
	
	rm_enode(dir, fileToRemove);
	
	fcount(file_sector,-1);
	
	return 0;
}


/*Remueve el archivo o directorio correspondiente al path pasado como primer argumento*/
int rm_shell(int argc, char* argv[]){

	if(argc<1){
		printf("usage: rm <pathname>\n");
		return -1;
	}	
	
	int error=0;
	
	if((error=_rm(argv[0]))==-1){
		printf("rm: error:%s\n",strerror(errno));
		return -1;
	}
	
	if(error==-2){
		printf("rm: The path %s is not allowed\n", argv[0]);
		return -1;
	}
	
	return 0;
}


/*Se cambia el directorio actual. El primer argumento es el path del directorio*/
int cd_shell(int argc, char* argv[]){
	if(argc<1){
		printf("usage: cd <pathname>\n");
		return -1;
	}
	char pathAux[MAX_PATH];
	strcpy(pathAux, argv[0]);
	/*Si es link lo resuelvo*/
	getLinkPath(pathAux);
	
	if(chdir(pathAux)==-1){
		printf("cd: error:%s\n",strerror(errno));
		return -1;
	}
	
	return 0;
}

/*Crea un node de tipo FIFO con nombre "name"*/
int mkfifo(char * name){
	return mknode(name,775,FIFO_TYPE);
}

/*Se crea un directorio. El primer argumento corresponde al path del mismo*/
int mkdir_shell(int argc, char* argv[]){

	if(argc<1){
		printf("usage: mkdir <pathname>\n");
		return -1;
	}
	/*Si es link lo resuelvo*/
	getParentLinkPath(argv[0]);
	
	if(mknode(argv[0],775,DIRECTORY_TYPE)==-1){
		printf("mkdir: error:%s\n",strerror(errno));
		return -1;
	}
	return 0;
}

/*Recivo como parametro un char con los permisos de archivos y lo paso a entero*/
int getMode(char * arg){
	
	if(strlen(arg) != 3)
		return -1;
	
	int i, mode, aux, modeAux;
	sscanf(arg,"%d",&mode);
	
	modeAux=mode;
	for(i=0; i < 3; i++){
		aux=modeAux % 10;
		if(aux < 0 || aux > 7)
			return -1;
		modeAux /= 10;
	}
	
	return mode;
	
}    


/*"Formatea" el disco, esto es: pisa el header del file system, para que la proxima vez que lo intente levantar no lo encuentre y cree uno nuevo*/
int format_shell(int argc, char* argv[]){
	format();
	return 1;
}

/*Cambia los permisos de un archivo. El primer argumento es el mode y el segundo el path al archivo*/
int chmod_shell(int argc, char* argv[]){
	
	if(argc<2){
		printf("usage: chmod <new mode> <pathname>\n");
		return -1;
	}
	
	int mode=getMode(argv[0]);

        if(mode == -1){
                printf("chmod: %s: invalid mode\n", argv[0]);
                return -1;
        }

	if(chmod(argv[1],mode)==0){
		printf("chmod: error:%s\n",strerror(errno));
                return -1;
	}
	
	return 0;
	
}
